iT邦幫忙

2022 iThome 鐵人賽

DAY 28
1

今天要介紹的是 Iterator 模式,我們就直接用例子來解釋,假設到了一間餐廳,服務員會來做接待,並且將菜單拿出來,服務員會將上面的菜色都先唸過一遍給客人知道。如果今天餐廳剛好牛排都賣完了,就不能再跟客人說還有牛排可以點,這時候我們會有兩種選擇。

第一種是跟服務員說今天牛排沒了,等一下看到菜單上有牛排的部分就不要說出來,我們想想看服務員除了要做很多事情外,還要記得不能將牛排說出來,這樣真的不是好方法,也有可能會忘記。那我們試試看第二種方式,直接在菜單上把牛排去除掉(或者劃掉),這樣服務員只需要照著菜單上有的餐點說出來就好,也簡單明瞭,更不怕會忘記。

也就是說,我們將菜單與服務員做解耦合,服務員要唸出所有餐點時,只需要知道照著菜單上有的餐點唸出來就好,而不是將餐點記在自己的腦中,每當有餐點賣完時就要去改變腦中的餐點邏輯。希望這樣解釋大家能夠理解,那我們直接來看範例吧!

Iterator - 定義

提供一種方法順序訪問一個聚合對象中各個元素,而又無須暴露該對象的內部表示。

https://ithelp.ithome.com.tw/upload/images/20221002/20136443mIPBbG9S8A.png

(圖片來源:https://www.wikiwand.com/en/Iterator_pattern#Media/File:Iterator_UML_class_diagram.svg)

範例 UML

https://ithelp.ithome.com.tw/upload/images/20221002/20136443Ohx2Rn3V2Y.png

Code要點

  • Menu會去繼承自IAggregate,代表菜單這個類別需要去實現迭代的功能,並且會在裡面回傳指定的Iterator實體。
  • MenuIterator即為Menu指定的Iterator實體,會去實作迭代功能,將菜單裡所有的餐點都輪播一遍。

不囉嗦上Code!

using System;
using System.Collections.Generic;

namespace DAY28_Iterator
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Menu Menu = new Menu();

            Menu.AddMeal(new Meal("牛排"));
            Menu.AddMeal(new Meal("漢堡"));
            Menu.AddMeal(new Meal("雞排"));
            Menu.AddMeal(new Meal("義大利麵"));

            Iterator iterator = Menu.Iterator();

            Console.WriteLine("菜單:");
            while (iterator.HasNext())
            {
                Meal meal = (Meal)iterator.Next();
                Console.WriteLine($"- {meal.GetMeal()}");
            }
        }
    }

    // 定義總計介面,需要執行迭代方法
    public interface IAggregate
    {
        public abstract Iterator Iterator();
    }

    public interface Iterator
    {
        // 確認是否有下個元素
        public abstract bool HasNext();

        // 執行下個元素
        public abstract object Next();
    }

    public class Meal
    {
        private string _name;
        public Meal(string name)
        {
            _name = name;
        }

        public string GetMeal()
        {
            return _name;
        }
    }

    // 需要實作 IAggregate,有迭代方法去列出菜單裡的內容
    public class Menu : IAggregate
    {
        private List<Meal> _meals;

        public Menu()
        {
            _meals = new List<Meal>();
        }

        public Meal GetMealIndex(int index)
        {
            return _meals[index];
        }

        public void AddMeal(Meal meal)
        {
            _meals.Add(meal);
        }

        public int GetLength()
        {
            return _meals.Count;
        }

        public Iterator Iterator()
        {
            return new MenuIterator(this);
        }

    }

    // 屬於 Menu 的 Iterator
    public class MenuIterator : Iterator
    {
        private Menu _menu;
        private int _index;

        public MenuIterator(Menu Menu)
        {
            _menu = Menu;
            _index = 0;
        }

        public bool HasNext()
        {
            if (_index < _menu.GetLength())
                return true;
            else
                return false;
        }

        public object Next()
        {
            Meal meal = _menu.GetMealIndex(_index);
            _index++;
            return meal;
        }
    }
}
  • 結果

https://ithelp.ithome.com.tw/upload/images/20221002/20136443h0D7rhH3zD.png

簡單的小結

Iterator 模式就是將迭代行為以及物件本身的實作細節分開,我們從範例中可以看到,在Main裡面去呼叫菜單後,只需要去判端HasNext()後,再去使用Next()方法即可將菜單裡所有餐點都輪播一遍。

如果我們今天要給菜單增加一個特別的邏輯,可能是要增加判斷說假日的話餐點都要做一些額外調整,但平日就一樣保持正常的邏輯,那們可以先增加一個HolidayMenuIterator, 在裡面去做專屬於假日時的邏輯判斷,接著將Menu類別新增建構子,在建構時將指定的Iterator傳入,並且回傳這個Iterator。這樣我們就可以讓服務生不用知道實際的邏輯細節,只需要照著菜單有的東西去做輪播,並且還能夠隨時的去變換菜單餐點迭代的邏輯!


上一篇
【DAY27】Chain of Responsibility模式 - 排程的背後原理
下一篇
【DAY29】State模式 - 升級成黃金會員的最後一哩路
系列文
勇闖秘境!探索物件導向背後的設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言